package com.niodata.dp.core.usermgr.op.kl;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.niodata.dp.core.DpConfiguration;
import com.niodata.dp.core.exception.ErrorCodes;
import com.niodata.dp.core.usermgr.DpUsermgrException;
import com.niodata.dp.log.LogUtil;
import com.niodata.dp.util.HttpCaller;
import com.niodata.dp.util.JsonUtil;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.DatatypeConverter;
import org.apache.http.HttpHost;
import org.apache.log4j.Logger;

/**
 * KDC，LDAP相关操作类.
 */
public class KdcLdapOperation {

  private static final Logger logger = Logger.getLogger(KdcLdapOperation.class);
  private static final KdcLdapOperation kdcLdapOperation;

  static {
    String urlPrefix = null;
    String proxyHost = null;
    int proxyPort = 80;
    if (DpConfiguration.isHadoopKerberosEnabled()) {
      urlPrefix = DpConfiguration.getString("kdcldap.urlprefix");
      boolean userProxy = DpConfiguration.getBoolean("kdcldap.useproxy");
      if (userProxy) {
        proxyHost = DpConfiguration.getString("kdcldap.proxyhost");
        proxyPort = DpConfiguration.getInt("kdcldap.proxyport");
      }
    }

    kdcLdapOperation = new KdcLdapOperation(urlPrefix, proxyHost, proxyPort);
  }

  private final String urlPrefix;
  private HttpHost proxy;

  private KdcLdapOperation(String urlPrefix, String proxyHost, int proxyPort) {
    this.urlPrefix = urlPrefix;
    if (proxyHost != null) {
      this.proxy = new HttpHost(proxyHost, proxyPort);
    }
  }

  public static KdcLdapOperation getInstance() {
    return kdcLdapOperation;
  }

  /**
   * change user password.
   *
   * @param userName username
   * @param encodedPassword encoded password
   * @throws DpUsermgrException exception
   */
  public void changePassword(String userName, String encodedPassword)
        throws DpUsermgrException {
    if (!DpConfiguration.isHadoopKerberosEnabled()) {
      return;
    }
    Message ret = null;
    try {
      Map<String, String> params = new HashMap();
      params.put("user", userName);
      params.put("password", encodedPassword);
      String body = JsonUtil.toJson(params);
      ret = HttpCaller
            .post(Message.class, urlPrefix + "/ng/v1/password", null, null,
                  body, 20, proxy);
    } catch (IOException e) {
      LogUtil.logStackTrace(logger, e);
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "HTTP Exception.");
    }
    if (ret == null) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "Response Null.");
    } else if (!ret.status.equalsIgnoreCase("SUCCESS")) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, ret.status);
    }

  }

  /**
   * 创建用户并返回keytab.
   *
   * @param userName 用户名(loginName/hdfsPrefix+groupId)
   * @return byte[] 字节数组
   * @throws DpUsermgrException 用户管理模块异常
   */
  public byte[] createUserAndReturnKeyTab(String userName, String encodedPassword)
        throws DpUsermgrException {
    Message ret;
    try {
      Map<String, String> params = new HashMap();
      params.put("user", userName);
      params.put("password", encodedPassword);
      String body = JsonUtil.toJson(params);
      ret = HttpCaller
            .post(Message.class, urlPrefix + "/ng/v1/user", null, null,
                  body, 20, proxy);
    } catch (IOException e) {
      LogUtil.logStackTrace(logger, e);
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "HTTP Exception.");
    }
    if (ret != null && ret.status.equalsIgnoreCase("SUCCESS")) {
      return DatatypeConverter.parseBase64Binary(ret.keytab);
    } else {
      if (ret == null) {
        throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "Response Null.");
      }
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, ret.status);
    }
  }

  /**
   * 移除用户并从相关组中移除.
   *
   * @param userName 用户名(loginName/hdfsPrefix+groupId)
   * @param groupNames 用户所在所有组名(groupPrefix+groupId)
   * @throws DpUsermgrException 用户管理模块异常
   */
  public void removeUser(String userName, List<String> groupNames)
        throws DpUsermgrException {
    if (!DpConfiguration.isHadoopKerberosEnabled()) {
      return;
    }
    Message ret;
    try {
      ret = HttpCaller
            .delete(Message.class, urlPrefix + "/ng/v1/user", null, null,
                  "{\"user\":\"" + userName + "\",\"groups\":" + JsonUtil.toJson(groupNames)
                        + "}", 20,
                  proxy);
    } catch (IOException e) {
      LogUtil.logStackTrace(logger, e);
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "HTTP Exception.");
    }
    if (ret == null) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "Response Null.");
    }
    if (!ret.status.equalsIgnoreCase("SUCCESS")) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, ret.status);
    }

  }

  /**
   * 创建组.
   *
   * @param groupName 组名(groupPrefix+groupId)
   * @param userName Master用户名(hdfsPrefix+groupId)
   * @throws DpUsermgrException 用户管理模块异常
   */
  public void createGroup(String groupName, String userName) throws DpUsermgrException {
    if (!DpConfiguration.isKerberosEnabled()) {
      return;
    }
    Message ret;
    try {
      ret = HttpCaller
            .post(Message.class, urlPrefix + "/ng/v1/group", null, null,
                  "{\"group\":\"" + groupName + "\",\"owner\":\"" + userName
                        + "\"}", 20, proxy);
    } catch (IOException e) {
      LogUtil.logStackTrace(logger, e);
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "HTTP Exception.");
    }
    if (ret == null) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "Response Null.");
    }
    if (!ret.status.equalsIgnoreCase("SUCCESS")) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, ret.status);
    }
  }

  /**
   * 删除组.
   *
   * @param groupName 组名(groupPrefix+groupId)
   * @throws DpUsermgrException 用户管理模块异常
   */
  public void removeGroup(String groupName) throws DpUsermgrException {
    if (!DpConfiguration.isKerberosEnabled()) {
      return;
    }
    Message ret;
    try {
      ret = HttpCaller
            .delete(Message.class, urlPrefix + "/ng/v1/group", null, null,
                  "{\"group\":\"" + groupName + "\"}", 20,
                  proxy);
    } catch (IOException e) {
      LogUtil.logStackTrace(logger, e);
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "HTTP Exception.");
    }
    if (ret == null) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "Response Null.");
    }
    if (!ret.status.equalsIgnoreCase("SUCCESS")) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, ret.status);
    }
  }

  /**
   * 将用户添加进组.
   *
   * @param userName 用户名(loginName/hdfsPrefix+groupId)
   * @param groupName 组名(groupPrefix+groupId)
   * @throws DpUsermgrException 用户管理模块异常
   */
  public void addUserToGroup(String userName, String groupName) throws DpUsermgrException {
    if (!DpConfiguration.isKerberosEnabled()) {
      return;
    }
    Message ret;
    try {
      ret = HttpCaller
            .post(Message.class, urlPrefix + "/ng/v1/relation", null, null,
                  "{\"group\":\"" + groupName + "\",\"user\":\"" + userName
                        + "\"}", 20, proxy);
    } catch (IOException e) {
      LogUtil.logStackTrace(logger, e);
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "HTTP Exception.");
    }
    if (ret == null) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "Response Null.");
    }
    if (!ret.status.equalsIgnoreCase("SUCCESS")) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, ret.status);
    }
  }

  /**
   * 将用户从组内移除.
   *
   * @param userName 用户名(loginName/hdfsPrefix+groupId)
   * @param groupName 组名(groupPrefix+groupId)
   * @throws DpUsermgrException 用户管理模块异常
   */
  public void removeUserFromGroup(String userName, String groupName)
        throws DpUsermgrException {
    Message ret;
    try {
      ret = HttpCaller
            .delete(Message.class, urlPrefix + "/ng/v1/relation", null, null,
                  "{\"group\":\"" + groupName + "\",\"user\":\"" + userName
                        + "\"}", 20,
                  this.proxy);
    } catch (IOException e) {
      LogUtil.logStackTrace(logger, e);
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "HTTP Exception.");
    }
    if (ret == null) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, "Response Null.");
    }
    if (!ret.status.equalsIgnoreCase("SUCCESS")) {
      throw new DpUsermgrException(ErrorCodes.ERROR_KDC, ret.status);
    }
  }

  private static class Message {

    String status;
    String keytab;

    public Message(@JsonProperty("status") String status, @JsonProperty("keytab") String keytab) {
      this.status = status;
      this.keytab = keytab;
    }

  }

}